<?php
declare(strict_types=1);
/**
 * This file is part of Hyperf Mall.
 *
 * @link     https://gitee.com/scwlkj/hypref_mall
 * contact  hyperf_mall@163.com
 */

namespace App\Cache;


use App\Common\DataConvert;
use App\Common\Singleton;
use Hyperf\Redis\Redis;
use Hyperf\Utils\ApplicationContext;
use Psr\Container\ContainerExceptionInterface;
use Psr\Container\NotFoundExceptionInterface;

abstract class BaseHashCache
{
    use Singleton;

    /**
     * 存储数据
     * @var mixed
     */
    protected $data;

    /**
     * @var Redis
     */
    protected static $redis;

    /**
     * 缓存key
     * @var string
     */
    protected static $cacheKey;


    /**
     * @throws ContainerExceptionInterface
     * @throws NotFoundExceptionInterface
     */
    protected function __construct()
    {
        $container = ApplicationContext::getContainer();
        self::$redis = $container->get(Redis::class);
    }

    /**
     * 获取数据
     *
     * @param string|int $key
     * @return mixed
     */
    public function get($key)
    {
        $key = strval($key);
        if (!isset($this->data[$key])) {
            $this->loadData($key);
        }
        return empty($this->data[$key]) ? null : $this->data[$key];
    }

    /**
     * Notes:加载数据
     * @param string|int $key 主键
     */
    public function load($key)
    {
        //从数据库加载整理
        $data = $this->loadFromModel($key);
        $data = $this->formatDataFromModel($data);
        //插入缓存
        $this->save($key, $data);
    }


    /**
     * Notes: 保存数据
     * @param string|int $key
     * @param mixed $data
     */
    public function save($key, $data)
    {
        $this->data[$key] = $data;
        $this->saveToCache($key, $data);
    }

    /**
     * 保存到缓存
     * @param string|int $key 主键key
     * @param mixed $data 需要保存的数据
     */
    public function saveToCache($key, $data)
    {
        self::$redis->hSet(static::$cacheKey, $key, DataConvert::encode($data));
    }

    /**
     * Notes:从缓存获取数据
     * @param string|int $key
     * @return mixed
     */
    public function getToCache($key)
    {
        $data = self::$redis->hGet(static::$cacheKey, $key);
        if (!is_null($data)) {
            return DataConvert::decode($data);
        }
        return null;
    }

    /**
     * Notes:清空全部缓存
     */
    public function deleteCacheAll()
    {
        //清除全部缓存
        self::$redis->del([static::$cacheKey]);
    }

    /**
     * Notes:批量删除
     * @param string[] $keys
     */
    public function deleteCacheBatch(array $keys)
    {
        self::$redis->hDel(static::$cacheKey, ...$keys);
        $this->data = [];
    }

    /**
     * 删除缓存
     * @param string|int $key
     */
    public function deleteCache($key)
    {
        self::$redis->hDel(static::$cacheKey, $key);
        unset($this->data[$key]);
    }

    /**
     * Notes:从缓存加载数据
     * @param string|int $key
     */
    public function loadData($key)
    {
        $this->data[$key] = $this->getToCache($key);
        if (is_null($this->data[$key])) {    //没有数据，从数据库加载
            $this->load($key);
        }
    }

    /**
     * 从模型中加载
     * @param string|int $key
     * @return mixed
     */
    abstract public function loadFromModel($key);

    /**
     * 检查数据并格式化
     * @param mixed $data
     * @return mixed
     */
    abstract public function formatDataFromModel($data);
}
